#include <string.h>
#include <iostream>
#include "matrixUtilities.h"

using namespace std;
#define LOC(i, j, n) matrix[((i) * (n) + (j))]

void rotateMatrix(int *matrix, unsigned int n) {
	if (matrix == NULL) {
		return;
	}

	unsigned int i, j;
	int temp;
	for (i = 0; i < n/2; i++) {
		for (j = i; j < n - 1 - i; j++) {
			temp = LOC(i, j, n);
			LOC(i, j, n) = LOC(n - 1 - j, i, n);
			LOC(n - 1 - j, i, n) = LOC(n - 1 - i, n - 1 - j, n);
			LOC(n - 1 - i, n - 1 - j, n) = LOC(j, n - 1 - i, n);
			LOC(j, n - 1 - i, n) = temp;
		}
	}

	return;
}


void printMatrix(int *matrix, unsigned int n) {
	unsigned int i, j;
	int temp;
	for (i = 0; i < n/2; i++) {
		for (j = i; j < n - 1 - i; j++) {
			cout << LOC(i, j, n) << "\t";
		}
		cout << endl;

		for (j = i; j < n - 1 - i; j++) {
			cout << LOC(j, n - 1 - i, n) << "\t";
		}
		cout << endl;

		for (j = i; j < n - 1 - i; j++) {
			cout << LOC(n - 1 - i, n - 1 - j, n) << "\t";
		}
		cout << endl;
	
		for (j = i; j < n - 1 - i; j++) {
			cout << LOC(n - 1 - j, i, n) << "\t";
		}
		cout << endl;
	}

	if ((n % 2) == 1) {
		cout << LOC(n/2, n/2, n) << endl;
	}

	return;
}

bool setRowZeros(int *matrix, 
				 unsigned int i,
				 unsigned int m, 
				 unsigned int n) {
	if (matrix == NULL) {
		cout << "Input matrix is NULL." << endl;
		return false;
	}

	if (n == 0 || m == 0 || i >= m) {
		cout << "Input argument error!" << endl;
		return false;
	}

	memset(&matrix[i * n], 0, sizeof(int) * n);

	return true;
}

bool setColumnZeros(int *matrix, 
					unsigned int j,
					unsigned int m,
					unsigned int n) {
	if (matrix == NULL) {
		cout << "Input matrix pointer, NULL!" << endl;
		return false;
	}

	if (m == 0 || n == 0 || j >= n) {
		cout << "Input argument error, NULL!" << endl;
		return false;
	}

	unsigned int index;
	for (index = 0; index < m; index++) {
		matrix[index * n + j] = 0;
	}

	return true;
}

bool setRowColumnZeros(int *matrix, unsigned int m, unsigned int n) {
	if (matrix == NULL) {
		cout << "Input matrix pointer is NULL." << endl;
		return false;
	}

	bool *row_flag = (bool *)malloc(n * sizeof(bool));
	if (row_flag == NULL) {
		cout << "Allocate row flag error, NULL." << endl;
		return false;
	}
	memset(row_flag, 0, sizeof(bool) * n);

	bool *column_flag = (bool *)malloc(m * sizeof(bool));
	if (column_flag == NULL) {
		cout << "Allocate column flag error, NULL." << endl;
		return false;
	}
	memset(column_flag, 0, sizeof(bool) * m);
	
	unsigned int i, j;
	for (i = 0; i < m; i++) {
		for (j = 0; j < n; j++) {
			if (row_flag[j] == false && 
			    column_flag[i] == false) {
				if (matrix[i * n + j] == 0) {
					row_flag[j] = true;
					column_flag[i] = true;
					if (!setRowZeros(matrix, i, m, n)) {
						cout << "Set row " << i << " error!" << endl;
						return false;
					}

					if (!setColumnZeros(matrix, j, m, n)) {
						cout << "Set column " << j << " error!" << endl;
						return false;
					}
				}
			}
		}
	}

	
	free(row_flag);
	free(column_flag);

	return true;
}

